//
//  main.cpp
//  RandomForest-AndreaBalboni
//
//  Created by Andrea Balboni on 05/04/12.
//  Copyright (c) 2012 Università degli Studi di Modena e Reggio Emilia. All rights reserved.
//

#include "TrainingData.h"
#include "RandomForest.h"
#include <time.h>
#include <iostream>
#include <fstream>
#include "Timer.h"



int main(int argc, const char * argv[])
{

    srand(time(NULL));
    //Seleziono il dataset
    std::string filename_training="numeri/optdigits.training.txt";
    //std::string filename_training="numeri/Numeri_decimal.data";
    
    //Carico il dataset per il training
    TrainingData<float> td;
    if(!td.readData(filename_training)){
        std::cerr<<"Errore di apertura per il file: "<<filename_training<<std::endl;
        return 1;
    }
    //random_shuffle(td.begin(),td.end());
    
    std::string filename_testing="numeri/optdigits.testing.txt";
    //std::string filename_testing="numeri/Numeri_decimal.data";
    //Carico il dataset per il training
    TrainingData<float> testd;
    if(!testd.readData(filename_testing)){
        return 1;
    }
    
    
   
    
    //Creo la foresta di alberi
    RandomForest<float> randomForestRandom;
    RandomForest<float>randomForestFisher;
    RandomForest<float>randomForestGini;
    unsigned int maxTrees=100;
    unsigned int forestStep=10;
    unsigned int maxDepth=30;
    unsigned int depthStep=5;
    unsigned int currentForest=0;
    unsigned int currentDepth=5;
//    time_t start_time_random, time_duration_random_t, time_duration_random_c=0;
//    time_t start_time_fisher, time_duration_fisher_t, time_duration_fisher_c=0;
//    time_t start_time_gini, time_duration_gini_t, time_duration_gini_c=0;
    Timer timerRandom, TimerGini, TimerFisher;
    double time_duration_random_t, time_duration_random_c, time_duration_fisher_t, time_duration_fisher_c, time_duration_gini_t, time_duration_gini_c;
    std::ofstream reportFile("/Users/andrea/Desktop/Report.txt");
    if (!reportFile){
        std::cout<<"Impossibile creare file di report"<<std::endl;
        return 2;
    }
    std::ofstream reportFileDepthRandom("/Users/andrea/Desktop/ReportDepthRandom.txt");
    if (!reportFileDepthRandom){
        std::cout<<"Impossibile creare file di report"<<std::endl;
        return 2;
    }
    std::ofstream reportFileDepthFisher("/Users/andrea/Desktop/ReportDepthFisher.txt");
    if (!reportFileDepthFisher){
        std::cout<<"Impossibile creare file di report"<<std::endl;
        return 2;
    }
    std::ofstream reportFileDepthGini("/Users/andrea/Desktop/ReportDepthGini.txt");
    if (!reportFileDepthGini){
        std::cout<<"Impossibile creare file di report"<<std::endl;
        return 2;
    }
    //reportFileDepthRandom<<"#Trees \t depth \t Misclassified \t Total \t Error \% \t Correct \% \t Train time \t Classif. time"<<std::endl;
    //reportFileDepthFisher<<"#Trees \t depth \t Misclassified \t Total \t Error \% \t Correct \% \t Train time \t Classif. time"<<std::endl;
    //reportFileDepthGini<<"#Trees \t depth \t Misclassified \t Total \t Error \% \t Correct \% \t Train time \t Classif. time"<<std::endl;
     for(; currentDepth<=maxDepth; currentDepth+=depthStep){

         for (; currentForest<=maxTrees; currentForest+=forestStep) {
             if(currentForest==0)
                 continue;
       
             //I parametri sono: dataset, numero alberi, profondità, tipo soglia 
            //(THRESH_FISHER oppure THRESH_RANDOM oppure THRESH_GINI)
            //start_time_random=time(NULL);
             timerRandom.start();
            randomForestRandom.createForest(td, currentForest,currentDepth, THRESH_RANDOM,true,1000);
             timerRandom.stop();
             time_duration_random_t=timerRandom.getElapsedTimeInSec();
             //time_duration_random_t=time(NULL)-start_time_random;
            //start_time_fisher=time(NULL);
             TimerFisher.start();
            randomForestFisher.createForest(td, currentForest, currentDepth,THRESH_FISHER,true,1000);
             TimerFisher.stop();
             time_duration_fisher_t=TimerFisher.getElapsedTimeInSec();
             TimerGini.start();
            //time_duration_fisher_t=time(NULL)-start_time_fisher;
            //start_time_gini=time(NULL);
            randomForestGini.createForest(td, currentForest,currentDepth, THRESH_GINI,true,1000);
             TimerGini.stop();
             time_duration_gini_t=TimerGini.getElapsedTimeInSec();
             //time_duration_gini_t=time(NULL)-start_time_gini;
            //Calcolo gli errori di classificazione
            float errorRandom=0.0;
            float errorFisher=0.0;
            float errorGini=0.0;
            time_duration_random_c=0;
            time_duration_fisher_c=0;
            time_duration_gini_c=0;
            for(unsigned int i=0; i < testd.size(); ++i) {
                //start_time_random=time(NULL);
                timerRandom.start();
                unsigned int cRandom = randomForestRandom.classify(testd.getRecord(i));
                //time_duration_random_c+=time(NULL)-start_time_random;
                timerRandom.stop();
                time_duration_random_c+=timerRandom.getElapsedTimeInSec();
                cv::Mat_<double> record;
                testd.getRecordMat(i, record);
                //start_time_fisher=time(NULL);
                TimerFisher.start();
                unsigned int cFisher = randomForestFisher.classifyFisher(record);
                TimerFisher.stop();
                time_duration_fisher_c+=TimerFisher.getElapsedTimeInSec();
                //time_duration_fisher_c+=time(NULL)-start_time_fisher;
                //start_time_gini=time(NULL);
                TimerGini.start();
                unsigned int cGini = randomForestGini.classify(testd.getRecord(i));
                TimerGini.stop();
                time_duration_gini_c+=TimerGini.getElapsedTimeInSec();
                //time_duration_gini_c+=time(NULL)-start_time_gini;
                if(cRandom!=testd.getRecord(i).getClass())
                    errorRandom++;
                if(cFisher!=testd.getRecord(i).getClass())
                    errorFisher++;
                if(cGini!=testd.getRecord(i).getClass())
                    errorGini++;
                
            }
            
//            /* Stampo gli errori e le percentuali*/
            std::cout<<"Classificazione con "<<currentForest<<" alberi con depth "<<currentDepth<<std::endl<<std::endl;
            //std::cout<<"Classificazione con "<<currentForest<<" alberi con altezza automatica"<<std::endl<<std::endl;
            std::cout<<"Classificazione Random in "<<time_duration_random_t<<" s di T e "<<time_duration_random_c<<" s di C"<<std::endl;
            std::cout<<"Sbagliati: "<<errorRandom<<" su " <<testd.size()<<std::endl;
            std::cout<<"Errore: "<<errorRandom/testd.size()*100<<" %"<<std::endl;
            std::cout<<"Giusti: "<<(1-errorRandom/testd.size())*100<<" %"<<std::endl;
            std::cout<<"Classificazione Fisher in "<<time_duration_fisher_t<<" s di T e "<<time_duration_fisher_c<<" s di C"<<std::endl;
            std::cout<<"Sbagliati: "<<errorFisher<<" su " <<testd.size()<<std::endl;
            std::cout<<"Errore: "<<errorFisher/testd.size()*100<<" %"<<std::endl;
            std::cout<<"Giusti: "<<(1-errorFisher/testd.size())*100<<" %"<<std::endl;
            std::cout<<"Classificazione Gini in "<<time_duration_gini_t<<" s di T e "<<time_duration_gini_c<<" s di C"<<std::endl;
            std::cout<<"Sbagliati: "<<errorGini<<" su " <<testd.size()<<std::endl;
            std::cout<<"Errore: "<<errorGini/testd.size()*100<<" %"<<std::endl;
            std::cout<<"Giusti: "<<(1-errorGini/testd.size())*100<<" %"<<std::endl;
            std::cout<<std::endl;
        
            /* Stampo gli errori e le percentuali*/
            //reportFile<<"Classificazione con "<<currentForest<<" alberi con altezza automatica"<<std::endl<<std::endl;
            reportFile<<"Classificazione con "<<currentForest<<" alberi con depth "<<currentDepth<<std::endl<<std::endl;
            reportFile<<"Classificazione Random in "<<time_duration_random_t<<" s di T e "<<time_duration_random_c<<" s di C"<<std::endl;
            reportFile<<"Sbagliati: "<<errorRandom<<" su " <<testd.size()<<std::endl;
            reportFile<<"Errore: "<<errorRandom/testd.size()*100<<" %"<<std::endl;
            reportFile<<"Giusti: "<<(1-errorRandom/testd.size())*100<<" %"<<std::endl;
            reportFile<<"Classificazione Fisher in "<<time_duration_fisher_t<<" s di T e "<<time_duration_fisher_c<<" s di C"<<std::endl;
            reportFile<<"Sbagliati: "<<errorFisher<<" su " <<testd.size()<<std::endl;
            reportFile<<"Errore: "<<errorFisher/testd.size()*100<<" %"<<std::endl;
            reportFile<<"Giusti: "<<(1-errorFisher/testd.size())*100<<" %"<<std::endl;
            reportFile<<"Classificazione Gini in "<<time_duration_gini_t<<" s di T e "<<time_duration_gini_c<<" s di C"<<std::endl;
            reportFile<<"Sbagliati: "<<errorGini<<" su " <<testd.size()<<std::endl;
            reportFile<<"Errore: "<<errorGini/testd.size()*100<<" %"<<std::endl;
            reportFile<<"Giusti: "<<(1-errorGini/testd.size())*100<<" %"<<std::endl;
            reportFile<<std::endl;
            
            reportFileDepthRandom<<errorRandom/testd.size()*100<<"\t";
            reportFileDepthFisher<<errorFisher/testd.size()*100<<"\t";
            reportFileDepthGini<<errorGini/testd.size()*100<<"\t";
             //reportFileDepthFisher<<currentForest<<"\t"<<currentDepth<<"\t"<<errorFisher<<"\t"<<testd.size()<<"\t"<<errorFisher/testd.size()*100<<"\t"<<(1-errorFisher/testd.size())*100<<"\t"<<time_duration_fisher_t<<"\t"<<time_duration_fisher_c<<std::endl;
            //reportFileDepthGini<<currentForest<<"\t"<<currentDepth<<"\t"<<errorGini<<"\t"<<testd.size()<<"\t"<<errorGini/testd.size()*100<<"\t"<<(1-errorGini/testd.size())*100<<"\t"<<time_duration_gini_t<<"\t"<<time_duration_gini_c<<std::endl;
        }
        currentForest=0;
         reportFileDepthRandom<<std::endl;
         reportFileDepthFisher<<std::endl;
         reportFileDepthGini<<std::endl;
    }
    reportFileDepthRandom.close();
    reportFileDepthFisher.close();
    reportFileDepthGini.close();
    reportFile.close();

    return 0;
}
